/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.lcfgly.Cache;

import com.lcfgly.Interface.GetCacheMark;
import com.lcfgly.Interface.ICache;
import com.lcfgly.Interface.UpdateCacheMark;
import com.lcfgly.util.ConfigDate;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

/**
 *
 * @author lcfgly
 */
@Component
@Aspect
public class CacheAop {

    static final Logger log = Logger.getLogger("Memcache");
    static final Logger error = Logger.getRootLogger();

    @Autowired
    @Qualifier("memcache")
    ICache cache;

    @Around("@annotation(anno)")
    public Object get(ProceedingJoinPoint call, GetCacheMark anno) throws Throwable {
        if (ConfigDate.config("cache").equals("true")) {
            String keys = getKeyNameFromParam(anno.value(), call);
            Object value = cache.get(keys);
            if (value == null) {
                log.info("未查询到 " + keys + " 缓存");
                value = call.proceed();
                cache.save(keys, value, anno.time());
                log.info(keys + " 添加到缓存");
            } else {
                log.info("查询到 " + keys + " 缓存");
            }
            return value;
        } else {
            return call.proceed();
        }
    }

    @Around("@annotation(anno)")
    public Object update(ProceedingJoinPoint call, UpdateCacheMark anno) throws Throwable {
        if (ConfigDate.config("cache").equals("true")) {
            String[] keys = new String[anno.value().length];
            int i = 0;
            for (String string : anno.value()) {
                keys[i++] = getKeyNameFromParam(string, call);
            }
            Object value = call.proceed();
            new UpdateThread(keys, cache).start();
            return value;
        } else {
            return call.proceed();
        }
    }

    /**
     *
     * @Title: getKeyNameFromParam
     * @Description: 获得组合后的KEY值
     * @param @param key
     * @param @param jp
     * @param @return
     * @return String
     * @throws
     */
    private String getKeyNameFromParam(String key, ProceedingJoinPoint jp) {
        if (!key.contains("$")) {
            return key;
        }
        String regexp = "\\$\\{[^\\}]+\\}";
        Pattern pattern = Pattern.compile(regexp);
        Matcher matcher = pattern.matcher(key);
        List<String> names = new ArrayList<String>();
        try {
            while (matcher.find()) {
                names.add(matcher.group());
            }
            key = executeNames(key, names, jp);
        } catch (Exception e) {
            error.error(e);
        }
        return key;
    }

    /**
     *
     * @Title: executeNames
     * @Description: 对KEY中的参数进行替换
     * @param @param key
     * @param @param names
     * @param @param jp
     * @param @return
     * @param @throws OgnlException
     * @return String
     * @throws
     */
    private String executeNames(String key, List<String> names, ProceedingJoinPoint jp) {
        Object[] arg = jp.getArgs();
        for (String name : names) {
            String temp = name.substring(2);
            temp = temp.substring(0, temp.length() - 1);
            String[] sub = temp.split("\\.");
            String value;
            if (sub.length > 1) {
                value = Value(arg[Integer.valueOf(sub[0])], sub[1]);
            } else {
                value = arg[Integer.valueOf(temp)].toString();
            }
            key = myReplace(key, name, value);
        }
        return key;
    }

    /**
     *
     * @Title: myReplace
     * @Description: 不依赖Regex的替换，避免$符号、{}等在String.replaceAll方法中当做Regex处理时候的问题。
     * @param @param src
     * @param @param from
     * @param @param to
     * @param @return
     * @return String
     * @throws
     */
    private String myReplace(String src, String from, String to) {
        int index = src.indexOf(from);
        if (index == -1) {
            return src;
        }
        return src.substring(0, index) + to + src.substring(index + from.length());
    }

    /**
     * 获取属性值
     *
     * @param arg
     * @param key
     * @return
     */
    private String Value(Object arg, String key) {
        try {
            StringBuilder sb = new StringBuilder(key);
            sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
            Method m = arg.getClass().getMethod("get" + sb.toString());
            return m.invoke(arg, new Object[]{}).toString();
        } catch (NoSuchMethodException ex) {
            log.error("NoSuchMethodException", ex);
        } catch (SecurityException ex) {
            log.error("SecurityException", ex);
        } catch (IllegalAccessException ex) {
            log.error("IllegalAccessException", ex);
        } catch (IllegalArgumentException ex) {
            log.error("IllegalArgumentException", ex);
        } catch (InvocationTargetException ex) {
            log.error("InvocationTargetException", ex);
        }
        return key;
    }

}
